package pl.com.photogetter;

/**
 * @author Piotr Maślany
 */

import java.io.*;
import java.security.*;
import java.text.*;
import java.util.*;

import javax.swing.*;

import com.drew.imaging.jpeg.*;
import com.drew.metadata.*;
import com.drew.metadata.exif.*;


public class Sorter extends Thread {

	private GUI parent;
	private HashMap files;
	private static String sep = System.getProperty("file.separator", "/");
	private Properties properties;

	public Sorter(GUI gui, Properties props, HashMap files) {
		parent = gui;
		this.files = files;
		properties = props;
	}

	public void run() {
		Set keys = files.keySet();
		Iterator iter = keys.iterator();
		int progress = 0;
		int all = files.size();
		parent.message("Do przetworzenia: "+all+" zdjęć.");
		int succeded = 0;
		int failed = 0;
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				parent.setallProgress(0);
			}
		});

		while (iter.hasNext()) {
			progress++;
			final int percent = progress;
			final File tmp = (File) files.get(iter.next());
			boolean result = doFile(tmp);
			if (result) {succeded++;} else {failed++;}

			SwingUtilities.invokeLater(new Runnable() {
				public void run() {
					parent.setallProgress(percent);
				}
			});
		}
		parent.message("Przetwarzanie zakończone");
		parent.message("Poprawnie przetworzono: " + succeded + " 	zdjęć");
		if (failed > 0)
		{
			parent.message("Nie przetworzono: " + failed + " zdjęć");			
		}
	}
	public static String calculateMD5SUM(File Filename) {

		String MD5SUM = new String();
		;

		try {
			MessageDigest md = MessageDigest.getInstance("md5");
			FileInputStream in = new FileInputStream(Filename);
			int len;
			byte[] data = new byte[1024];
			while ((len = in.read(data)) > 0) {
				//MessageDigest updaten
				md.update(data, 0, len);
			}
			in.close();

			//MessageDigest berechnen und ausgeben

			byte[] result = md.digest();
			for (int i = 0; i < result.length; ++i) {
				MD5SUM = MD5SUM + toHexString(result[i]);
			}
		} catch (Exception e) {
			System.err.println("[MD5Calculator] failed: " + e.toString());
		}
		return MD5SUM;

	}

	public static String toHexString(byte b) {

		int value = (b & 0x7F) + (b < 0 ? 128 : 0);
		String ret = (value < 16 ? "0" : "");
		ret += Integer.toHexString(value).toUpperCase();
		return ret;
	}

	private boolean copyFile(ImagePile file) {

		
		if (file.getNewFilename().exists()) {
			String newmd5 = calculateMD5SUM(file.getNewFilename());
			System.err.println(
				file.getNewFilename().getName() + " " + newmd5 + " -> " + file.getFileName().getName() + " " + file.getMD5SUM());
			if (newmd5.equals(file.getMD5SUM())) {
				parent.message(
					"Plik już istnieje - pominięto:" + file.getFileName().getName());
				return false;
			}
		}
		/* Examine new Filename */
		while (file.getNewFilename().exists()) {
			String Filename = "_" + file.getNewFilename().getName();
			file.setNewFilename(
				new File(file.getNewFilename().getParent() + sep + Filename));
			Filename = null;
		}

		/* Check if the parent directories are there */

		File tmpPath = file.getNewFilename().getParentFile();
		LinkedList dirList = new LinkedList();
		while (!tmpPath.exists()) {
			dirList.add(tmpPath);
			tmpPath = tmpPath.getParentFile();
		}

		/* Create missing parent directories */
		while (!dirList.isEmpty()) {
			File newDir = (File) dirList.removeLast();
			if (newDir.mkdir()) {
				//
			} else {
				System.err.println(
					"Wystąpił błąd podczas tworzenia docelowego katalogu!");
				System.exit(1);
			}
		}

		/*
		 * Actually copy the file using BufferedReader this should go into
		 * seperate class, does it?
		 */

		/** A buffered inputstream for copying */
		BufferedInputStream is;
		/** A buffered Outputstream for copying */
		BufferedOutputStream os;

		try {
			is =
				new BufferedInputStream(
					new FileInputStream(file.getFileName()));
			os =
				new BufferedOutputStream(
					new FileOutputStream(file.getNewFilename()));

			int b;
			while ((b = is.read()) != -1) {
				os.write(b);
			}
			is.close();
			os.close();
		} catch (FileNotFoundException e) {
			return false;
		} catch (IOException e) {
			return false;
		}
		return true;
	}

	private String adaptString(String input) {
		String output;
		
		if(System.getProperty("os.name").matches(".*indows.*"))
		{
			output = input.replaceAll("\\\\","\\\\\\\\");
		}
		else 
		{
			output = input;
		}
		
		return output;
		
	}

	private boolean doFile(File file) {
		boolean success = true;
		ImagePile imageProperties = null;

		try
		{
			imageProperties = getImageData(file);	
		}
		catch (Exception e)
		{
			parent.message("Dla pliku: " + file.getName() + " brak danych EXIF.");
			System.out.println("Dla pliku: " + file.getName() + " brak danych EXIF." + e.getMessage());
			throw new RuntimeException(e);
		}
		
		
		imageProperties.setMD5SUM(calculateMD5SUM(file));

		success = this.copyFile(imageProperties);

		if(success) {
			parent.message("Przetworzono plik: " + file.getName());
		}
		else {
			parent.message("Przetworzono plik: " + file.getName() + " bez kopiowania.");
			return false;
		}
		return true;
	}

	/* fetch the EXIF Data */
	private ImagePile getImageData(File filename) 
	{
		ImagePile exifMetaData;
		File myFile = filename;
		exifMetaData = new ImagePile(myFile);
		
		Calendar cal = Calendar.getInstance();

		Date myDate = new Date();
		DateFormat df = DateFormat.getDateInstance();

		Metadata metadata = new Metadata();
		Directory exifDirectory;
		
		try 
		{
			metadata = JpegMetadataReader.readMetadata(myFile);
			exifDirectory = metadata.getDirectory(ExifDirectory.class);
		} catch (JpegProcessingException e) 
		{
			return returnUnknownDirectory(filename, exifMetaData);
		}

		if (exifDirectory.containsTag(ExifDirectory.TAG_MAKE)) {
			exifMetaData.setCameraMaker(
				exifDirectory.getString(ExifDirectory.TAG_MAKE));
		}

		if (exifDirectory.containsTag(ExifDirectory.TAG_MODEL)) {
			exifMetaData.setCameraModel(
				exifDirectory.getString(ExifDirectory.TAG_MODEL));
		}

		if (!exifDirectory.containsTag(ExifDirectory.TAG_APERTURE)) {
			if (exifDirectory.containsTag(ExifDirectory.TAG_MAX_APERTURE)) {
				exifMetaData.setApertureTime(
					exifDirectory.getString(ExifDirectory.TAG_MAX_APERTURE));
			}
		} else {
			exifMetaData.setApertureTime(
				exifDirectory.getString(ExifDirectory.TAG_APERTURE));
		}

		if (exifDirectory.containsTag(ExifDirectory.TAG_FLASH)) {
			exifMetaData.setFlashUsed(
				exifDirectory.getString(ExifDirectory.TAG_FLASH));
		}

		if (exifDirectory.containsTag(ExifDirectory.TAG_FOCAL_LENGTH)) {
			exifMetaData.setFocalLength(
				exifDirectory.getString(ExifDirectory.TAG_FOCAL_LENGTH));
		}

		if (exifDirectory.containsTag(ExifDirectory.TAG_EXIF_IMAGE_WIDTH)) {
			exifMetaData.setWidth(
				exifDirectory.getString(ExifDirectory.TAG_EXIF_IMAGE_WIDTH));
		}

		if (exifDirectory.containsTag(ExifDirectory.TAG_EXIF_IMAGE_HEIGHT)) {
			exifMetaData.setHeight(
				exifDirectory.getString(ExifDirectory.TAG_EXIF_IMAGE_HEIGHT));
		}

		if (!exifDirectory.containsTag(ExifDirectory.TAG_SHUTTER_SPEED)) {
			if (exifDirectory.containsTag(ExifDirectory.TAG_EXPOSURE_TIME)) {
				exifMetaData.setExposureTime(
					exifDirectory.getString(ExifDirectory.TAG_EXPOSURE_TIME));
			}
		} else {
			exifMetaData.setExposureTime(
				exifDirectory.getString(ExifDirectory.TAG_SHUTTER_SPEED));
		}

		
		if (exifDirectory.containsTag(ExifDirectory.TAG_DATETIME_DIGITIZED)) {
			try {
				myDate =	exifDirectory.getDate(ExifDirectory.TAG_DATETIME_DIGITIZED);
			} catch (MetadataException e1) {
				// TODO Auto-generated catch block
				parent.message(e1.toString());
			}
		} else {
			myDate = new Date();
	}

	exifMetaData.setImageDate(myDate);

	cal.setTime(myDate);

	String Year = beautifyNumbers(cal.get(Calendar.YEAR));
	String Month = beautifyNumbers(cal.get(Calendar.MONTH) + 1);
	String Day = beautifyNumbers(cal.get(Calendar.DAY_OF_MONTH));
	String Hour = beautifyNumbers(cal.get(Calendar.HOUR_OF_DAY));
	String Minute = beautifyNumbers(cal.get(Calendar.MINUTE));
	String Second = beautifyNumbers(cal.get(Calendar.SECOND));

	String NewPath;
	String complex = properties.getProperty("COMPLEX");
	String separator = properties.getProperty("SEPARATOR");
	if (separator == null || separator.equals("")) {separator = "_";}
	if (complex == null || complex.matches("FALSE"))
	{
		NewPath =
			properties.getProperty("PHOTODIR")
				+ sep
				+ Year
				+ separator
				+ Month
				+ separator
				+ Day
				+ sep
				+ filename.getName();		
	}
	else
	{
		NewPath =
			properties.getProperty("PHOTODIR")
				+ sep
				+ Year
				+ sep
				+ Month
				+ sep
				+ Day
				+ sep
				+ filename.getName();
	}
	

	exifMetaData.setNewFilename(new File(NewPath));

	return exifMetaData;
}

	private ImagePile returnUnknownDirectory(File filename,
			ImagePile exifMetaData) {
		String NewPath =
			properties.getProperty("PHOTODIR")
				+ sep
				+ "BEZ_DATY"
				+ sep
				+ filename.getName();
		exifMetaData.setNewFilename(new File(NewPath));
		return exifMetaData;
	}
	
	private String beautifyNumbers(int input) {
		String output;
		
		if(Integer.toString(input).length() == 1) {
			output = "0" + input; 
		}
		else {
			output = Integer.toString(input);
		}
		return output;
	}

}
